package com.chinaoct.siku.gzw.report;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Slf4j
@Component
public class GzwDbReport {

    @Value("${gzw.DSP_DATA_TYPE}")
    private String DSP_DATA_TYPE;

    @Value("${gzw.file_path}")
    private String basePath;

    private final static String BUSINESS_CODE1 = "91440300190346175T_1162_1007_";
    private final static String BUSINESS_CODE2 = "91440300190346175T_1168_1001_";

    public Map<String,String> report(String path, List<String> filePaths,String dataDate,Integer enableFile) throws Exception {
        Date date = new Date();
        Calendar calender = Calendar.getInstance();
        calender.setTime(date);
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        String dateNumber = new SimpleDateFormat("yyyyMMddHHmmss").format(calender.getTime());
        String sysPath=isLinux(path+"\\");
        // 上报数据 1162
        String rootPath= isLinux(basePath + "\\1161");
        log.info("1162 开始生成文件");
        String dbName =BUSINESS_CODE1+dateNumber+"_"+uuid+".db";
        createDBV2(rootPath,dbName,sysPath,filePaths,dataDate,1162);
        String dbZipName =BUSINESS_CODE1+dateNumber+"_"+uuid+".zip";
        String structuredData = createStructuredData(rootPath, dbZipName, null,BUSINESS_CODE1);
        log.info(structuredData);
        uploadFile(rootPath,structuredData);

        String dbZipName1 = null;
        StringBuffer buffer = new StringBuffer();
        String rootPath1= isLinux(basePath + "\\1167");
        if(null!=enableFile && 1 == enableFile.intValue()){
            log.info("1168 开始生成DB文件");
            String uuid1 = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
            String dateNumber1 = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String dbName1 =BUSINESS_CODE2+dateNumber1+"_"+uuid1+".db";
            createDBV2(rootPath1,dbName1,sysPath,filePaths,dataDate,1168);
            dbZipName1 =BUSINESS_CODE2+dateNumber1+"_"+uuid1+".zip";


            log.info("1168 开始生成附件文件");
            //将处理好的非结构化数据打包成对应的zip
            String uuid2 = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
            String dateNumber2 = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String dbZipName2 =BUSINESS_CODE2+dateNumber2+"_"+uuid2+".zip";
            List<String> unstructuredData = createGenerateUnstructuredDataV2(rootPath1, dateNumber2, 102400000*5, dbZipName2,dbZipName1,BUSINESS_CODE2);
            //上传附件

            for(String unstructuredDatum:unstructuredData){
                log.info(unstructuredDatum);
                buffer.append(unstructuredDatum).append(",");
                uploadFile(rootPath1,unstructuredDatum);
            }
            String structuredData1 = createStructuredData(rootPath1, dbZipName1, unstructuredData,BUSINESS_CODE2);
            log.info(structuredData1);
            uploadFile(rootPath1,structuredData1);
        }


        Map<String,String> map = new HashMap<>();
        map.put("1162",dbZipName);
        map.put("1168-1",dbZipName1);
        map.put("1168-2",buffer.toString());
        // 删除文件夹
        deleteFolder(rootPath1);
        return map;
    }

    private void deleteFolder(String rootPath1) {
        String zipFilePath = isLinux(rootPath1 + "\\非结构化数据");
        File file = new File(zipFilePath);
        File[] files = file.listFiles();
        for (File file1:files){
            if(file1.getName().indexOf(BUSINESS_CODE2)>=0 && file1.isDirectory()){
                File[] files2 = file1.listFiles();
                for(File file2:files2){
                    file2.delete();
                }
                if(file1.exists()){
                    file1.delete();
                }
            }
        }
    }


    private HashMap<String, String> createDBV2(String rootPath, String dbName, String path, List<String> filePaths,String dataDate,Integer code) throws Exception{
        HashMap<String, String> table = new HashMap<>();

        //目标db地址
        String dbPath = isLinux(rootPath + "\\结构化数据");
        //清空结构化数据下文件
        File oldFile=new File(dbPath);
        if(!oldFile.exists()){
            oldFile.mkdirs();
        }
        File[] oldFiles = oldFile.listFiles();
        if (oldFiles != null && oldFiles.length>0) {
            for(File f:oldFiles){
                f.delete();
            }
        }
        //源db地址
        String resourcePath = isLinux(rootPath + "\\db");
        File file = new File(resourcePath);
        File[] listFiles = file.listFiles();
        if (listFiles == null) {
            log.info(file.getAbsolutePath());
            throw  new RuntimeException("获取不到原DB模板文件");
        }
        File oldDBFile = listFiles[0];
        String newDBFilePath = isLinux(dbPath + "\\" + dbName);
        // File newDBFile = new File(newDBFilePath);
        Path destinationPath = Paths.get(newDBFilePath);
        Files.copy(oldDBFile.toPath(),destinationPath, StandardCopyOption.REPLACE_EXISTING);
        //oldDBFile.renameTo(newDBFile);

        //创建表
        DBUtils.setConnection(newDBFilePath);
        List<Map<String, String>> tableInformations = DBUtils.select("SELECT INFO_RES_ID,INFO_RES_NAME FROM hadwn_info_res_tab");
        for (Map<String, String> tableInformation : tableInformations) {
            Map<String, String> map = new HashMap<>();
            String infoResId = tableInformation.get("INFO_RES_ID");
            String infoResName = tableInformation.get("INFO_RES_NAME");
            StringBuilder sqlFieldNames = new StringBuilder();
            sqlFieldNames.append("SELECT\n" +
                    "\tINDX_ID AS INDX_ID, /*生成表时, COL_+INDX_ID值作为表字段名,按照INDX_ID值升序生成表字段*/\n" +
                    "\tINDX_NM, /*采集的信息项（即：采集指标）*/\n" +
                    "\tINDX_DATA_TYPE, /*生成表时,通过INDX_DATA_TYPE值获取表字段的数据类型*/\n" +
                    "\tINDX_DATA_LEN, /*生成表时,通过INDX_DATA_LEN值获取表字段的数据长度*/\n" +
                    "\tINDEX_DESC, /*通过INDEX_DESC值获取指标填写说明*/ \n" +
                    "\tINDEX_NOTES, /*通过INDEX_DESC值获取指标填写说明*/ \n" +
                    "\tIS_FILE, /* 判断是否是附件字段,若是附件字段,表字段值填写能够关联到非结构化文件的文件名（“32位文件MD5值【大写】_文件自有名字.文件类型” ）,若涉及多个附件,文件名用英文逗号分隔*/\n" +
                    "\tIS_NULL /*生成表时,判断字段是否为空,是表示可以为空,否表示不可以为空*/ \n" +
                    "FROM\n" +
                    "\tHADWN_INDX_TAB\n" +
                    "WHERE\n" +
                    "\tINFO_RES_ID = '");
            sqlFieldNames.append(infoResId);
            sqlFieldNames.append("' /*以3031271180信息资源为例*/ \n" +
                    "ORDER BY INDX_ID ASC;");
            List<Map<String, String>> fieldNames = DBUtils.select(sqlFieldNames.toString());
            String tableName = "R_DB_" + infoResId;
            if(code.intValue() == 1162){
                DBUtils.createTableAndInsertData(tableName, fieldNames,rootPath,path,filePaths,DSP_DATA_TYPE);
            }else  if(code.intValue() == 1168){
                DBUtils.createTableAndInsertData2(tableName, fieldNames,rootPath,path,filePaths,DSP_DATA_TYPE,dataDate);

            }
            table.put(infoResName, tableName);
        }
        //删除辅助表
        DBUtils.dropTable("hadwn_assis_tab");
        DBUtils.dropTable("hadwn_indx_tab");
        DBUtils.dropTable("hadwn_info_res_tab");
        //这里不关闭连接  等数据全部插入完成之后关闭
        DBUtils.endConnection();
        return table;
    }

    private static void uploadFile(String rootPath, String structuredData) throws Exception {
        String filePath = isLinux(rootPath + "\\") + structuredData;
        File file = new File(filePath);
        String url="http://172.16.12.74:8080/dezj-dataacq2/dataexchange/public/api/uploadFile";
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httppost = new HttpPost(url);
        try {

            httppost.setHeader("time","20220519094025");
            httppost.setHeader("sign","658fd3c65e89f27a20ea8f91db9f8e3e");
            //httppost.setHeader("Content-Type","multipart/form-data");
            RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(1200000).setConnectionRequestTimeout(1200000).setSocketTimeout(1200000).build();
            httppost.setConfig(defaultRequestConfig);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("file",file);
            httppost.setEntity(builder.build());
            CloseableHttpResponse response = httpclient.execute(httppost);
            String result = EntityUtils.toString(response.getEntity(), "utf-8");
            JSONObject jsonObject = JSONObject.parseObject(result);
            if(jsonObject.getInteger("Error")==0){
                log.info("文件上传成功");
            }else {
                log.error(result);
                throw new Exception("文件上传失败");
            }
        }  finally {
            if (null != httppost){
                httppost.releaseConnection();
            }
            if(null!=file && file.exists()){
                file.delete();
            }
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
    /**
     * 生成结构化数据包
     *
     * @param rootPath
     * @param dbZipName
     * @param fileNames
     * @return
     */
    public static String createStructuredData(String rootPath, String dbZipName, List<String> fileNames,String code) throws IOException {
        String filePath = isLinux(rootPath + "\\结构化数据");
        String zipFilePath = rootPath;
        //生成db.xml文件
        createDbXml(filePath, fileNames);
        //生成结构化zip包
        createZip(filePath, zipFilePath, dbZipName, null, null,code);
        //因为生成的包和传入的dbZipName名称一致，所以直接返回dbZipName
        return dbZipName;
    }

    /**
     * 生成db.xml方法
     */
    public static void createDbXml(String path, List<String> fileZipNameTexts) throws IOException {
        try {
            Document document = DocumentHelper.createDocument();
            Element log = document.addElement("log");
            if (fileZipNameTexts != null) {
                Element fileZips = log.addElement("fileZips");
                for (String fileZipNameText : fileZipNameTexts) {
                    Element fileZipName = fileZips.addElement("fileZipName");
                    fileZipName.setText(fileZipNameText);
                }
            }
            OutputFormat outputFormat = OutputFormat.createPrettyPrint();
            outputFormat.setEncoding("UTF-8");
            outputFormat.setIndentSize(4);
            XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(isLinux(path + "\\" + "db.xml")), outputFormat);
            xmlWriter.write(document);
            xmlWriter.close();
        } finally {
        }
    }

    /**
     * 生成非结构化数据包
     *
     * @param rootPath    要上传的包地址
     * @param dateNumber  日期  例如20220501121020
     * @param fileMaxSize 单个文件大小
     * @param dbZipName   dbZip的名字
     * @throws IOException
     */
    public static List<String> createGenerateUnstructuredDataV2(String rootPath, String dateNumber, Integer fileMaxSize, String ZipName,String dbZipName,String code) throws IOException {
        String filePath = isLinux(rootPath + "\\非结构化数据\\附件");
        String zipFilePath = isLinux(rootPath + "\\非结构化数据");
        String zipFileName = ZipName;

        //根据附件大小限制打成压缩包
        List<String> zipNames = createZip(filePath, zipFilePath, zipFileName, dateNumber, fileMaxSize,code);

        if (zipNames == null) {
            new File(filePath).delete();
            new File(zipFilePath).delete();
            return null;
        }

        //为每个附件压缩包生成非结构化文件夹
        File file2 = new File(zipFilePath);
        for (File file : file2.listFiles()) {
            String directory = file.getName().replace(".zip", "");
            String directoryPath = isLinux(zipFilePath + "\\" + directory);
            new File(directoryPath).mkdir();
            File file1 = new File(isLinux(directoryPath + "\\" + file.getName()));
            file.renameTo(file1);
            createFileXml(directoryPath, dbZipName);
        }
        //将每个非结构化文件夹打成压缩包
        for (String zipName : zipNames) {
            String path = isLinux(zipFilePath + "\\" + zipName.replace(".zip", ""));
            createZip(path, rootPath, zipName, dateNumber, null,BUSINESS_CODE2);
        }
        return zipNames;
    }

    /**
     * 生成file.xml方法
     */
    public static void createFileXml(String path, String dbZipNameText) {
        try {
            Document document = DocumentHelper.createDocument();
            Element log = document.addElement("log");
            Element dbZipName = log.addElement("dbZipName");
            dbZipName.setText(dbZipNameText);
            OutputFormat outputFormat = OutputFormat.createPrettyPrint();
            outputFormat.setEncoding("UTF-8");
            outputFormat.setIndentSize(4);
            XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(isLinux(path + "\\" + "file.xml")), outputFormat);
            xmlWriter.write(document);
            xmlWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("file.xml失败");
        }
    }

    /**
     * 生成压缩包并返回生成的压缩包名称
     *
     * @param filePath    要压缩的文件
     * @param zipFilePath 生成压缩包的位置
     * @param zipFileName 生成压缩包的名称  如果为null  自己根据dateNumber随机生成
     * @param dateNumber  当前数据 格式20220513171126
     * @param fileMaxSize 单个压缩包最大大小 单位字节  为null时全部文件打成一个压缩包
     * @return
     * @throws IOException
     */
    public static List<String> createZip(String filePath, String zipFilePath, String zipFileName, String dateNumber, Integer fileMaxSize,String code) throws IOException {
        ArrayList<String> zipNames = new ArrayList<>();
        //非结构化数据：处理下载的附件，根据500m大小的限制打成压缩包（大于500就打成多个压缩包
        File file1 = new File(filePath);
        if (file1.listFiles().length == 0) {
            return null;
        }
        long fileSize = 0;
        //生成随机32位uuid
        String uuid = getUUid();
        //附件压缩包名称
        String zipAttName;
        if (zipFileName == null) {
            zipAttName = code + dateNumber + "_" + uuid + ".zip";
        } else {
            zipAttName = zipFileName;
        }
        zipNames.add(zipAttName);
        //附件压缩包环境
        String zipAttNamePath = isLinux(zipFilePath + "\\" + zipAttName);
        //创建压缩包
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipAttNamePath), Charset.forName("UTF-8"));
        for (File listFile : file1.listFiles()) {
            long length = listFile.length();
            // log.warn("文件名称：{}，文件大小：{}",listFile.getName(),length);
            if (fileMaxSize != null && fileSize + length > fileMaxSize) {
                zipOutputStream.closeEntry();
                zipOutputStream.flush();
                zipOutputStream.close();
                uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
                zipAttName = code + dateNumber + "_" + uuid + ".zip";
                zipAttNamePath = isLinux(zipFilePath + "\\" + zipAttName);
                zipOutputStream = new ZipOutputStream(new FileOutputStream(zipAttNamePath), Charset.forName("UTF-8"));
                zipNames.add(zipAttName);
                fileSize = 0;
            }
            ZipEntry zipEntry = new ZipEntry(listFile.getName());
            zipOutputStream.putNextEntry(zipEntry);
            byte[] bytes = new byte[Math.toIntExact(length)];
            FileInputStream fileInputStream = new FileInputStream(listFile);
            int len;
            while ((len = fileInputStream.read(bytes)) > 0) {
                zipOutputStream.write(bytes, 0, len);
            }
            //关闭压缩包打包
            fileInputStream.close();
            //            listFile.delete();
            fileSize += length;
        }
        zipOutputStream.closeEntry();
        zipOutputStream.flush();
        zipOutputStream.close();
        //        file1.delete();
        return zipNames;
    }

    /**
     * 判断是否是linux系统,对//符号进行处理
     *
     * @return
     */
    public static String isLinux(String filePath) {
        String os = System.getProperty("os.name");
        if (os.contains("Windows")) {
            return filePath.replace("/", "\\");
        } else {
            return filePath.replace("\\", "/");
        }
    }

    public static String getUUid() {
        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }

}
